#version 410

out vec4 out_Color;

uniform sampler2D u_depthTX;
uniform sampler2D u_normalTX;
uniform sampler2D u_diffuseTX;
uniform sampler2D u_miscTX;

uniform float u_Near;
uniform float u_Far;

uniform int u_gbufferView;

in vec2 fs_Texcoord;

// Code from : http://aras-p.info/texts/CompactNormalStorage.html
vec3 unpackNormal(vec2 encNorm) {
	vec2 fenc = encNorm*4.0f - 2.0f;
	float f = dot(fenc, fenc);
	float g = sqrt(1.0f -.25f*f);
	return vec3(fenc*g,1.0f - .5f*f);
}

vec4 packFloatTo4x8(in float val) {
	uint a = floatBitsToInt(val);
	return vec4((bitfieldExtract(a,0,8))/256.0f,
				(bitfieldExtract(a,8,8))/256.0f,
				(bitfieldExtract(a,16,8))/256.0f,
				(bitfieldExtract(a,24,8))/256.0f);
}

float unpack4x8ToFloat(in vec4 val) {
	uint a = uint(val.x*256.0f+.5f) + 
	uint(val.y*256.0f+.5f)*256u + 
	uint(val.z*256.0f+.5f)*256u*256u+
	uint(val.w*256.0f+.5f)*256u*256u*256u;
	return uintBitsToFloat(a);
}

// Packing and unpacking code courtesy of:
// http://www.ozone3d.net/blogs/lab/20080604/glsl-float-to-rgba8-encoder/
// http://olivers.posterous.com/linear-depth-in-glsl-for-real
vec4 pack2FloatTo4x8(in vec2 val) {
	const vec2 bitSh = vec2(256.0f, 1.0f);
	const vec2 bitMsk = vec2(0.0f, 1.0f/256.0f);
	vec2 res1 = fract(val.x * bitSh);
	res1 -= res1.xx * bitMsk;
	vec2 res2 = fract(val.y * bitSh);
	res2 -= res2.xx * bitMsk;
	return vec4(res1.x,res1.y,res2.x,res2.y);
}

vec2 unpack4x8To2Float(in vec4 val) {
	const vec2 unshift = vec2(1.0f/256.0f, 1.0f);
	return vec2(dot(val.xy, unshift), dot(val.zw, unshift));
}

float linearizeDepth(float exp_depth, float near, float far) {
    return	(2 * near) / (far + near -  exp_depth * (far - near)); 
}

void main(void) {
	switch(u_gbufferView) {
		case 2:
			vec3 normal = unpackNormal(unpack4x8To2Float(texture(u_normalTX, fs_Texcoord)));
			out_Color = vec4(.5f*normal + .5f, 1.0f);
			break;
		case 7:
			out_Color = vec4(unpack4x8To2Float(texture(u_normalTX, fs_Texcoord)), 0.0f, 1.0f);
			break;
		case 3:
			out_Color = vec4(texture(u_diffuseTX, fs_Texcoord).xyz, 1.0f);
			break;
		case 4:
			out_Color = vec4(texture(u_miscTX, fs_Texcoord).xy, .0f, 1.0f);
			break;
		case 5:
			float linDepth = linearizeDepth(unpack4x8ToFloat(texture(u_depthTX, fs_Texcoord)), u_Near, u_Far);
			//float linDepth = unpack4x8ToFloat(texture(u_depthTX, fs_Texcoord));
			if(linDepth > .001f)
				out_Color = vec4(linDepth, linDepth, linDepth, 1.0f);
			else
				out_Color = vec4(1.0f);
			break;
		case 6:
			float objID = texture(u_miscTX, fs_Texcoord).z;;
			out_Color = vec4(objID*32.0f, objID*16.0f, objID*8.0f, 1.0f);
			break;
		default:
			out_Color = vec4(.2f, .5f, .8f, 1.0f);
			break;
	}
}